package org.lex.expression.ui;

import java.awt.BorderLayout;
import java.awt.event.InputEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;

import org.lex.expression.ExpressionCalculator;
import org.lex.expression.ExpressionParser;
import org.lex.expression.PostfixExpression;
import org.lex.expression.tree.ExpressionTree;
import org.lex.io.IO;


public class CalculatorPane extends JPanel {
	private JSplitPane mainSplitPane = null;
	private TitledPane inputPane = null;
	private TitledPane outputPane = null;
	private JSplitPane buttomSplitPane = null;
	private TreePane treePane = null;

	public CalculatorPane() {
		super();
		initialize();
	}

	private void initialize() {
		this.setSize(300, 200);
		this.setLayout(new BorderLayout());
		this.add(getMainSplitPane(), BorderLayout.CENTER);
	}

	private JSplitPane getMainSplitPane() {
		if (mainSplitPane == null) {
			mainSplitPane = new JSplitPane();
			mainSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
			mainSplitPane.setTopComponent(getInputPane());
			mainSplitPane.setResizeWeight(0.1D);
			mainSplitPane.setDividerLocation(75);
			mainSplitPane.setBottomComponent(getButtomSplitPane());
			mainSplitPane.setDividerSize(6);
		}
		return mainSplitPane;
	}

	private TitledPane getInputPane() {
		if (inputPane == null) {
			inputPane = new TitledPane("Input");
			inputPane.getTextArea().addKeyListener(new InputListener());
		}
		return inputPane;
	}

	private JSplitPane getButtomSplitPane() {
		if (buttomSplitPane == null) {
			buttomSplitPane = new JSplitPane();
			buttomSplitPane.setDividerSize(6);
			buttomSplitPane.setLeftComponent(getOutputPane());
			buttomSplitPane.setRightComponent(getTreePane());
			buttomSplitPane.setResizeWeight(0.6D);
		}
		return buttomSplitPane;
	}

	private TitledPane getOutputPane() {
		if (outputPane == null) {
			outputPane = new TitledPane("History");
			outputPane.getTextArea().setEditable(false);
		}
		return outputPane;
	}

	private TreePane getTreePane() {
		if (treePane == null) {
			treePane = new TreePane();
		}
		return treePane;
	}

	class InputListener extends KeyAdapter {
		private JTextArea input = null;
		private JTextArea output = null;
		// ==============================
		private ExpressionParser parser = null;
		private ExpressionCalculator calculator = null;
		private ExpressionTree treeParser = null;

		public InputListener() {
			super();
			this.input = getInputPane().getTextArea();
			this.output = getOutputPane().getTextArea();
			this.parser = new ExpressionParser();
			this.calculator = new ExpressionCalculator();
			this.treeParser = new ExpressionTree();
		}

		public void keyTyped(KeyEvent e) {
			// CTRL + Enter
			if (KeyEvent.VK_ENTER == e.getKeyChar() && InputEvent.CTRL_DOWN_MASK == e.getModifiersEx()) {
				String expr = input.getText().toLowerCase();
				input.setText("");
				if (true == this.isCommand(expr))
					return;
				String result = this.calculate(expr).toString();
				StringBuilder buffer = new StringBuilder(expr);
				buffer.append(IO.newline);
				buffer.append('\t');
				buffer.append(result);
				buffer.append(IO.newline);
				output.append(buffer.toString());
			}
		}

		private Number calculate(String expression) {
			PostfixExpression postfix = parser.parsePostfix(expression);
			getTreePane().setRootNode(treeParser.parseRootNode(postfix));
			Number result = calculator.calculate(postfix);
			return result;
		}

		private boolean isCommand(String expr) {
			if (expr.startsWith("help")) {
				output.append(this.getHelp());
				return true;
			} else if (expr.startsWith("exit") || expr.startsWith("quit")) {
				System.exit(0);
				return true;
			}
			return false;
		}

		private String getHelp() {
			return "Input expression, and press CTRL + Enter " + "to calculate the value." + IO.newline;
		}
	}
}
